/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


/*************************************************************************
 * File: http.cpp
 *************************************************************************
 *\author: starlove
 *************************************************************************/

#include <tools/http.h>
#include <platform/string.h>

int CHTTPParser::parse_length(const char *sz, unsigned int ns)
{
	char sztmp[255];
	int cs = ns;
	if(cs > 254)
		cs = 254;
	const char *s1 = strstr(sz, "\r\nContent-Length:");
	memcpy(sztmp, s1, cs);
	sztmp[cs] = 0;
	char *s = strstr(sztmp, ":");
	if(!s)
		return 0;
	s = trim(s, cs + sztmp - s);
	int l = 0;
	sscanf(s, "%d", &l);
	return l;
}

bool CHTTPParser::parse_request_action(const char *s, LPHTTP_ACTION pAction)
{
	const char *end = strstr(s, __MLSE_NETWORK_HTTP_LINE_DELIMITERS__);
	if(!end)
		return false;
	if(memcmp(s, "GET", 3) == 0)
	{
		pAction->tp = __MLSE_NETWORK_HTTP_GET__;
	}else if(memcmp(s, "POST", 4) == 0)
	{
		pAction->tp = __MLSE_NETWORK_HTTP_POST__;
	}else if(memcmp(s, "HEAD", 4) == 0)
	{
		pAction->tp = __MLSE_NETWORK_HTTP_HEAD__;
	}else if(memcmp(s, "OPTIONS", 7) == 0)
	{
		pAction->tp = __MLSE_NETWORK_HTTP_HEAD__;
	}

	const char *purl = strpbrk(s, " \t");
	if(!purl)
		return false;
	purl ++;
	const char *pver = strpbrk(purl, " \t");
	if(!pver)
		return false;
	pver ++;

	if(memcmp(pver, "HTTP/1.1", 8) == 0)
	{
		pAction->ver = __MLSE_NETWORK_HTTP_VER_1__;
	}else if(memcmp(pver, "HTTP/1.0", 8) == 0)
	{
		pAction->ver = __MLSE_NETWORK_HTTP_VER_0__;
	}else
		return false;

	unsigned int nurlsize = pver - purl - 1;

	unsigned int pqssize = 0;
	const char *pqs = strpbrk(purl, "?");
	if(pqs)
	{
		pqs ++;
		pqssize = nurlsize - (pqs - purl - 1);
		nurlsize -= pqssize;
	}

	if(nurlsize > 254 || pqssize > 254)
		return false;

	memcpy(pAction->url, purl, nurlsize);
	pAction->url[nurlsize] = 0;

	if(pqssize > 0)
		memcpy(pAction->qs, pqs, pqssize);
	pAction->qs[pqssize] = 0;

	return true;
}

const char *CHTTPParser::get_method_name(char tp)
{
    const char *szMethod = "";
    switch(tp)
    {
    	case __MLSE_NETWORK_HTTP_GET__:
    	{
    		szMethod = "GET";
    		break;
    	}
    	case __MLSE_NETWORK_HTTP_POST__:
    	{
    		szMethod = "POST";
    		break;
    	}
    	case __MLSE_NETWORK_HTTP_HEAD__:
    	{
    		szMethod = "HEAD";
    		break;
    	}
    	case __MLSE_NETWORK_HTTP_OPTIONS__:
    	{
    		szMethod = "OPTIONS";
    		break;
    	}
    	default:
			szMethod = "OTHER";
    }
    return szMethod;
}

bool CHTTPParser::build_response(LPNETWORKBUFFER pOut, LPHTTPRESPONSE pResponse, LPNETWORKBUFFER pIn)
{
	if(!pResponse)
		return NULL;
	LPBUFFER_WRAPPER pBuffer = pResponse->header.GetBuffer();
	LPWRAPPER_DATA_HEADER pHeader = (LPWRAPPER_DATA_HEADER)pBuffer->read(sizeof(WRAPPER_DATA_HEADER));
	if(!pHeader)
		return NULL;
	int ncount = pHeader->size;
	int n = 0;
	LPWRAPPER_KEYVALUE_DATA_HEADER p = NULL;

	pOut->AppendStr("HTTP/1.1 ");
	pOut->AppendStr(pResponse->status_code);
	pOut->AppendStr("\r\n");
	if(pIn->GetDataSize() > 0)
	{
		pOut->AppendStr("Content-Length: ");
		pOut->AppendStr( ConvertToStr<int>(pIn->GetDataSize()).c_str() );
		pOut->AppendStr("\r\n");
	}

	while((n < ncount) && (p = (LPWRAPPER_KEYVALUE_DATA_HEADER)pBuffer->read(sizeof(WRAPPER_KEYVALUE_DATA_HEADER))))
	{
		void *pKeyData = ((char *)p) + sizeof(WRAPPER_KEYVALUE_DATA_HEADER);
		void *pData = ((char *)pKeyData) + p->ksize;

		unsigned int nskip_size = p->ksize + p->size;

		switch (p->ktp)
		{
		case DTP_STR:
			{
				pOut->AppendStr((ENCODESTR)pKeyData);
			}
			break;
		default:
			{
				continue;
			}
		}
		pOut->AppendStr(":");

		switch (p->tp)
		{
		case DTP_STR:
			{
				pOut->AppendStr((ENCODESTR)pKeyData);
			}
			break;
		case DTP_INT:
			{
				pOut->AppendStr( ConvertToStr<int>(*(int *)pData).c_str() );
			}
			break;
		case DTP_BOOL:
			{
				pOut->AppendStr( (*(bool *)pData) ? "true" : "false" );
			}
			break;
		case DTP_FLOAT:
			{
				pOut->AppendStr( ConvertToStr<float>(*(float *)pData).c_str() );
			}
			break;
		case DTP_INT64:
			{
				pOut->AppendStr( ConvertToStr<INT64>(*(INT64 *)pData).c_str() );
			}
			break;
		case DTP_DOUBLE:
			{
				pOut->AppendStr( ConvertToStr<double>(*(double *)pData).c_str() );
			}
			break;
		default:
			{
				continue;
			}
		}

		pOut->AppendStr("\r\n");

		if(!pBuffer->skip(nskip_size))
		{
			DEBUG_INFO_CODEC("data buffer is invalid!");
			break;
		}
		n++;
	}

	pOut->AppendStr("\r\n");
	pOut->Append(pIn->GetPtr(), pIn->GetDataSize());
	return true;
}
